
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <stdarg.h>
#include <pthread.h>
#include <sys/time.h>
#include "clog.h"

static FILE *flog = NULL;
static pthread_mutex_t output_lock;
static long cflen = 0;

static char log_buf[MAX_BUF];
static char cache_buf[64*1024];
static char timestamp[100];
static char fpath[128];

static const char *ltexts[] = {"F", "E", "W", "I", "D", "T"};

static int _log_size_ = MAX_FILE_LEN; // Unit:Bytes, default 5M Bytes
static EM_LOG_LEVEL _log_level = EM_LOG_INFO;
static bool _en_std_out_ = false;
static bool _en_file_out_ = false;
int log_lock_num = 0;


void clog_set_log_size(int max_size)
{
    _log_size_ = max_size;
}

void clog_set_log_level(int log_level)
{
    _log_level = (EM_LOG_LEVEL)log_level;
}

void clog_set_log_stdout(bool en)
{
    _en_std_out_ = en;
}

void clog_set_log_fileout(bool en)
{
    _en_file_out_ = en;
}

int clog_init(char *path)
{
    /*init output mutex*/
    pthread_mutex_init(&output_lock, NULL);

    long flen = 0;

    snprintf(fpath, sizeof(fpath), "%s", path);

    flog = fopen(fpath, "a+");

    if (flog == NULL)
    {
        printf("clog init failed.\n");
        return -1;
    }

    fseek(flog, 0, SEEK_END);

    flen = ftell(flog);

    if (flen < _log_size_)
    {
        cflen = flen;
        return 0;
    }

    /*file len >= _log_size_, reopen*/
    flog = fopen(fpath, "w+");

    if (flog == NULL)
    {
        printf("clog reopen failed.");
        return -1;
    }

    cflen = 0;
    return 0;
}

void clog_exit(void)
{
    if (flog)
        fclose(flog);
    pthread_mutex_destroy(&output_lock);
}
#define LOG_TIME_USE 1
void clog_log(int level, const char *func, int line, const char *fmt, ...)
{
    int rc = 0;
    long log_len = 0;
#if LOG_TIME_USE
    time_t tt;
    struct tm *now;
    struct timeval tv;
#endif
    //pthread_t pid;
    
    if (level > _log_level)
        return;
    va_list list;

    /*lock write of file*/
    log_lock_num++;
    pthread_mutex_lock(&output_lock);
    va_start(list, fmt);

    /*get thread id*/
    //pid = pthread_self();

#if LOG_TIME_USE
    /*get localtime*/
    gettimeofday(&tv, NULL);
    tt = tv.tv_sec;
    now = localtime(&tt);
    strftime(timestamp, sizeof(timestamp), "%Y-%m-%d %H:%M:%S", now);
    log_len += snprintf(log_buf + log_len, sizeof(log_buf) - log_len, "[%s][%-s][%-s:%d] ",
                             timestamp,ltexts[level], func, line);
#else
    log_len += snprintf(log_buf + log_len, sizeof(log_buf) - log_len, "[%-s][%-s:%d] ",
                             //ltexts[level], func, line);
#endif
    log_len += vsnprintf(log_buf + log_len, sizeof(log_buf) - log_len, fmt, list);

    if (log_len < MAX_BUF - 1)
    {
        log_len += snprintf(log_buf + log_len, sizeof(log_buf) - log_len, "%s", "\n");
        log_buf[log_len] = '\0';
    }
    else
    {
        log_buf[MAX_BUF - 2] = '\n';
        log_buf[MAX_BUF - 1] = '\0';
        log_len = MAX_BUF - 1;
    }
    
    va_end(list);

    if (_en_file_out_)
    {
        if ((log_len + cflen) >= _log_size_)
        {
            printf("====log_len:%d, cflen:%d, _log_size_:%d \n\n", log_len, cflen, _log_size_);
            /*reopen file*/
            flog = fopen(fpath, "w+");

            if (flog == NULL)
            {
                printf("clog reopen failed.");
            }
            cflen = 0;
        }

        cflen += log_len;

        /*output*/
        if (flog)
        {
            fwrite(log_buf, 1, log_len, flog);
            fflush(flog);
        }
    }
    
    if (_en_std_out_)
    {
        fprintf(stdout, "%s", log_buf);
        //printf("%s", log_buf);
    }

    pthread_mutex_unlock(&output_lock);
    log_lock_num--;
}

void clog_dlog(int level, const char *fmt, ...)
{
    char dlog_buf[512];
    int rc = 0;
    long log_len = 0;

    time_t tt;
    struct tm *now;
    struct timeval tv;

    pthread_t pid;

    if (level > _log_level)
        return;
    va_list list;
    va_start(list, fmt);

    /*lock write of file*/
    log_lock_num++;
    pthread_mutex_lock(&output_lock);

    log_len += vsnprintf(dlog_buf + log_len, sizeof(dlog_buf) - log_len, fmt, list);

    if (log_len < 512 - 1)
    {
        dlog_buf[log_len] = '\0';
    }
    else
    {
        dlog_buf[512 - 1] = '\0';
        log_len = 512 - 1;
    }

    va_end(list);

    if (_en_file_out_)
    {
        if ((log_len + cflen) >= _log_size_)
        {
            printf("====log_len:%d, cflen:%d, _log_size_:%d \n\n", log_len, cflen, _log_size_);
            /*reopen file*/
            flog = fopen(fpath, "w+");

            if (flog == NULL)
            {
                printf("clog reopen failed.");
            }
            cflen = 0;
        }

        cflen += log_len;

        /*output*/
        if (flog)
        {
            fwrite(dlog_buf, 1, log_len, flog);
            fflush(flog);
        }
    }

    if (_en_std_out_)
    {
        printf("%s", dlog_buf);
    }

    pthread_mutex_unlock(&output_lock);
    log_lock_num--;
}
void clog_hex(char *msg, unsigned char *bin_data,unsigned short bin_len){
  cdlogd("%s:",msg);
  while(bin_len--)
    cdlogd("0x%02X ",*bin_data++);
  cdlogd("\r\n");
}